package com.campus.counseling.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.campus.counseling.entity.Appointment;
import com.campus.counseling.model.mapper.AppointmentMapper;
import com.campus.counseling.model.dto.AppointmentDTO;
import com.campus.counseling.model.dto.AppointmentQuery;
import com.campus.counseling.model.vo.AppointmentVO;
import com.campus.counseling.security.SecurityUser;
import com.campus.counseling.service.AppointmentService;
import com.campus.counseling.util.SecurityUtils;
import com.campus.counseling.model.common.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.time.temporal.ChronoUnit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.campus.counseling.entity.Schedule;
import com.campus.counseling.model.mapper.ScheduleMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Map;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
import com.campus.counseling.service.ChatService;
import com.campus.counseling.entity.ChatSession;
import com.campus.counseling.model.mapper.ChatSessionMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.campus.counseling.entity.Counselor;
import com.campus.counseling.model.mapper.CounselorMapper;
import com.campus.counseling.entity.ConsultationRecord;
import com.campus.counseling.service.ConsultationRecordService;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;


@Service
@RequiredArgsConstructor
public class AppointmentServiceImpl extends ServiceImpl<AppointmentMapper, Appointment> implements AppointmentService {

    private final AppointmentMapper appointmentMapper;
    private final ScheduleMapper scheduleMapper;
    private final ObjectMapper objectMapper;
    private final ChatService chatService;
    private final ChatSessionMapper chatSessionMapper;
    private final CounselorMapper counselorMapper;
    private final ConsultationRecordService consultationRecordService;
    private static final Logger log = LoggerFactory.getLogger(AppointmentServiceImpl.class);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAppointment(AppointmentDTO dto) {
        try {
            // 1. 检查该时间段是否在咨询师的排班中
            LocalDateTime appointmentTime = LocalDateTime.parse(dto.getAppointmentTime(),
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            LocalDate appointmentDate = appointmentTime.toLocalDate();

            // 获取当前时间
            LocalDateTime now = LocalDateTime.now();
            
            // 计算预约时间段的结束时间
            LocalDateTime endTime = appointmentTime.plusMinutes(60);

            if (now.isAfter(endTime)) {
                throw new ServiceException("该时间段已过期，无法预约");
            }

            // 获取咨询师信息
            Counselor counselor = counselorMapper.selectOne(
                new LambdaQueryWrapper<Counselor>()
                    .eq(Counselor::getId, dto.getCounselorId())
            );
            
            if (counselor == null) {
                throw new ServiceException("咨询师不存在");
            }

            log.info("查询排班信息 - 咨询师ID: {}, 预约日期: {}", dto.getCounselorId(), appointmentDate);

            // 使用counselor.getId()查询排班
            Schedule schedule = scheduleMapper.selectOne(new LambdaQueryWrapper<Schedule>()
                    .eq(Schedule::getCounselorId, dto.getCounselorId())  // 直接使用传入的counselorId
                    .eq(Schedule::getScheduleDate, appointmentDate));

            if (schedule == null) {
                log.error("未找到排班信息 - 咨询师ID: {}, 预约日期: {}", dto.getCounselorId(), appointmentDate);
                throw new ServiceException("该时间段咨询师未排班");
            }

            log.info("找到排班信息: {}", schedule);

            // 2. 检查时间段是否在排班中
            String timeSlot = getTimeSlot(appointmentTime);
            List<String> availableSlots = objectMapper.readValue(schedule.getTimeSlots(), new TypeReference<List<String>>() {});
            if (!availableSlots.contains(timeSlot)) {
                throw new ServiceException("该时间段不在排班范围内");
            }

            // 3. 检查是否已被预约
            boolean exists = appointmentMapper.exists(new LambdaQueryWrapper<Appointment>()
                    .eq(Appointment::getCounselorId, dto.getCounselorId())
                    .eq(Appointment::getAppointmentTime, appointmentTime)
                    .eq(Appointment::getStatus, "APPROVED"));

            if (exists) {
                throw new ServiceException("该时间段已被预约");
            }

            // 4. 创建预约
            Appointment appointment = new Appointment();
            BeanUtils.copyProperties(dto, appointment);
            appointment.setCounselorId(dto.getCounselorId());  // 直接使用传入的counselorId
            appointment.setStudentId(SecurityUtils.getUserId());
            appointment.setAppointmentTime(appointmentTime);
            appointment.setStatus("PENDING");
            appointmentMapper.insert(appointment);
            
        } catch (JsonProcessingException e) {
            log.error("解析排班时间段失败", e);
            throw new ServiceException("系统错误，请稍后重试");
        }
    }

    @Override
    public List<Map<String, Object>> getAvailableTimeSlots(Long counselorId, LocalDate date) {
        // 1. 获取当天的预约记录
        LambdaQueryWrapper<Appointment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Appointment::getCounselorId, counselorId)
                .eq(Appointment::getDeleted, false)
                .between(Appointment::getAppointmentTime,
                        date.atStartOfDay(),
                        date.atTime(LocalTime.MAX));

        List<Appointment> appointments = list(wrapper);

        // 2. 定义默认时间段
        List<String> defaultTimeSlots = Arrays.asList(
                "09:00-10:00", "10:00-11:00", "14:00-15:00", "15:00-16:00","16:00-17:00", "17:00-18:00"
        );

        // 3. 构建每个时间段的状态
        return defaultTimeSlots.stream()
                .map(timeSlot -> {
                    Map<String, Object> slot = new HashMap<>();
                    slot.put("timeSlot", timeSlot);

                    // 查找该时间段是否有预约
                    Optional<Appointment> appointment = appointments.stream()
                            .filter(apt -> {
                                LocalTime aptTime = apt.getAppointmentTime().toLocalTime();
                                String aptTimeStr = String.format("%02d:00-%02d:00",
                                        aptTime.getHour(),
                                        aptTime.getHour() + 1);
                                return timeSlot.equals(aptTimeStr);
                            })
                            .findFirst();

                    if (appointment.isPresent()) {
                        Appointment apt = appointment.get();
                        // 构建状态显示文本
                        String statusText = getStatusDisplayText(apt.getStatus(), apt.getStudentName());
                        slot.put("displayText", statusText);
                        slot.put("status", apt.getStatus());
                        slot.put("studentName", apt.getStudentName());
                        slot.put("appointmentId", apt.getId());
                    } else {
                        slot.put("displayText", "可预约");
                        slot.put("status", "AVAILABLE");
                        slot.put("studentName", null);
                        slot.put("appointmentId", null);
                    }

                    return slot;
                })
                .collect(Collectors.toList());
    }

    // 获取状态显示文本
    private String getStatusDisplayText(String status, String studentName) {
        switch (status) {
            case "CONFIRMED":
                return String.format("已预约 - %s", studentName);
            case "COMPLETED":
                return String.format("已完成 - %s", studentName);
            case "CANCELLED":
                return "已取消";
            case "PENDING":
                return String.format("待确认 - %s", studentName);
            default:
                return "可预约";
        }
    }

    // 获取时间段字符串，如 "09:00-10:00"
    private String getTimeSlot(LocalDateTime time) {
        return time.format(DateTimeFormatter.ofPattern("HH:mm")) + "-" +
                time.plusHours(1).format(DateTimeFormatter.ofPattern("HH:mm"));
    }

    @Override
    public Page<AppointmentVO> getAppointmentList(AppointmentQuery query) {
        log.info("查询预约列表 - 参数: {}", query);
        
        // 创建分页对象
        Page<Appointment> page = new Page<>(query.getPageNum(), query.getPageSize());
        
        // 使用 mapper 的关联查询方法
        Page<Appointment> appointmentPage = appointmentMapper.selectAppointmentPage(page, query);
        
        // 打印查询结果
        log.info("查询到预约记录数: {}", appointmentPage.getRecords().size());
        appointmentPage.getRecords().forEach(apt -> {
            log.info("预约记录详情: ID={}, 时间={}, 状态={}, 学生={}, 咨询师={}, 原始数据={}", 
                apt.getId(), 
                apt.getAppointmentTime(), 
                apt.getStatus(), 
                apt.getStudentName(),
                apt.getCounselorName(),
                apt
            );
        });
        
        // 转换为VO
        Page<AppointmentVO> voPage = new Page<>(
            appointmentPage.getCurrent(), 
            appointmentPage.getSize(), 
            appointmentPage.getTotal()
        );
        
        List<AppointmentVO> voList = appointmentPage.getRecords().stream()
            .map(this::convertToVO)
            .peek(vo -> log.info("转换后的VO: {}", vo))
            .collect(Collectors.toList());
        
        voPage.setRecords(voList);
        
        return voPage;
    }

    @Override
    @Transactional
    public void updateAppointment(AppointmentDTO dto) {
        // 获取当前预约记录
        Appointment appointment = appointmentMapper.selectById(dto.getId());
        if (appointment == null) {
            throw new RuntimeException("预约记录不存在");
        }

        // 更新状态
        appointment.setStatus(dto.getStatus());
        if ("CANCELLED".equals(dto.getStatus())) {
            appointment.setCancelReason(dto.getCancelReason());
        }

        // 更新时间
        appointment.setUpdateTime(LocalDateTime.now());

        // 执行更新
        appointmentMapper.updateById(appointment);
    }

    @Override
    @Transactional
    public void confirmAppointment(Long appointmentId) {
        // 获取预约信息
        Appointment appointment = getById(appointmentId);
        if (appointment == null) {
            throw new ServiceException("预约不存在");
        }

        // 检查预约状态
        if (!"PENDING".equals(appointment.getStatus())) {
            throw new ServiceException("只能确认待确认状态的预约");
        }

        // 检查当前用户是否为该预约的咨询师
        SecurityUser currentUser = SecurityUtils.getLoginUser();
        if (currentUser == null || !currentUser.getId().equals(appointment.getCounselorId())) {
            throw new ServiceException("只有咨询师本人才能确认预约");
        }

        // 更新预约状态
        appointment.setStatus("CONFIRMED");
        appointment.setUpdateTime(LocalDateTime.now());
        updateById(appointment);
        
        // 创建聊天会话
        ChatSession chatSession = chatService.getOrCreateSession(appointmentId);
        log.info("已创建聊天会话，ID：{}", chatSession.getId());
        
        // 创建咨询记录
        ConsultationRecord record = new ConsultationRecord();
        record.setAppointmentId(appointmentId);
        record.setStudentId(appointment.getStudentId());
        record.setCounselorId(appointment.getCounselorId());
        record.setConsultationTime(appointment.getAppointmentTime());
        record.setDuration(60); // 默认60分钟
        record.setCreateTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());
        consultationRecordService.addRecord(record);
        log.info("已创建咨询记录，ID：{}", record.getId());
    }

    @Override
    @Transactional
    public void cancelAppointment(Long appointmentId, String reason) {
        // 获取预约信息
        Appointment appointment = getById(appointmentId);
        if (appointment == null) {
            throw new ServiceException("预约不存在");
        }
        
        // 检查预约状态
        if ("CANCELLED".equals(appointment.getStatus())) {
            throw new ServiceException("预约已取消");
        }
        
        // 如果是已确认状态的预约，需要删除相关记录
        if ("CONFIRMED".equals(appointment.getStatus())) {
            // 删除聊天会话
            ChatSession chatSession = chatSessionMapper.selectOne(
                new LambdaQueryWrapper<ChatSession>()
                    .eq(ChatSession::getAppointmentId, appointmentId)
                    .eq(ChatSession::getDeleted, 0)
            );
            if (chatSession != null) {
                // 使用chatSessionMapper来更新
                int updated = chatSessionMapper.update(null,
                    new LambdaUpdateWrapper<ChatSession>()
                        .eq(ChatSession::getId, chatSession.getId())
                        .set(ChatSession::getDeleted, 1)
                        .set(ChatSession::getUpdateTime, LocalDateTime.now())
                );
                log.info("已删除聊天会话, sessionId: {}, 更新结果: {}", chatSession.getId(), updated > 0);
            }
            
            // 删除咨询记录
            ConsultationRecord record = consultationRecordService.getRecordByAppointmentId(appointmentId);
            if (record != null) {
                // 使用consultationRecordService来更新
                boolean updated = consultationRecordService.update(
                    new LambdaUpdateWrapper<ConsultationRecord>()
                        .eq(ConsultationRecord::getId, record.getId())
                        .set(ConsultationRecord::getDeleted, 1)
                        .set(ConsultationRecord::getUpdateTime, LocalDateTime.now())
                );
                log.info("已删除咨询记录, recordId: {}, 更新结果: {}", record.getId(), updated);
            }
        }
        
        // 更新预约状态 (这个可以直接用this.update因为是Appointment实体)
        boolean updated = this.update(
            new LambdaUpdateWrapper<Appointment>()
                .eq(Appointment::getId, appointmentId)
                .set(Appointment::getStatus, "CANCELLED")
                .set(Appointment::getCancelReason, reason)
                .set(Appointment::getUpdateTime, LocalDateTime.now())
                .set(Appointment::getDeleted, 1)
        );
        log.info("已取消预约, appointmentId: {}, 更新结果: {}", appointmentId, updated);
    }

    @Override
    public AppointmentVO getAppointmentDetail(Long id) {
        Appointment appointment = appointmentMapper.selectAppointmentById(id);
        return convertToVO(appointment);
    }

    @Override
    @Transactional
    public void revokeAppointment(Long id) {
        Appointment appointment = appointmentMapper.selectById(id);
        if (appointment == null) {
            throw new ServiceException("预约不存在");
        }

        // 检查状态
        if (!"CANCELLED".equals(appointment.getStatus())) {
            throw new ServiceException("只能撤回已取消的预约");
        }

        // 检查取消时间是否在24小时内
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime cancelTime = appointment.getUpdateTime();
        long hours = ChronoUnit.HOURS.between(cancelTime, now);
        if (hours > 24) {
            throw new ServiceException("取消超过24小时的预约不能撤回");
        }

        // 检查预约时间是否已过
        LocalDateTime appointmentTime = appointment.getAppointmentTime();
        if (now.isAfter(appointmentTime)) {
            throw new ServiceException("已过期的预约不能撤回");
        }

        // 恢复到取消前的状态（如果之前已确认则恢复为已确认，否则恢复为待确认）
        appointment.setStatus(appointment.getCancelReason().contains("已确认") ? "CONFIRMED" : "PENDING");
        appointment.setCancelReason(null);
        appointment.setUpdateTime(LocalDateTime.now());
        appointmentMapper.updateById(appointment);
    }

    private AppointmentVO convertToVO(Appointment appointment) {
        if (appointment == null) {
            return null;
        }
        
        AppointmentVO vo = new AppointmentVO();
        BeanUtils.copyProperties(appointment, vo);
        
        // 确保日期时间格式化
        if (appointment.getAppointmentTime() != null) {
            String formattedTime = appointment.getAppointmentTime().format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
            );
            log.info("格式化时间: 原始值={}, 格式化后={}", 
                appointment.getAppointmentTime(), 
                formattedTime
            );
            vo.setAppointmentTime(formattedTime);
        }
        
        return vo;
    }

    @Override
    public List<Appointment> getAppointmentsByDateRange(Long counselorId, LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<Appointment> wrapper = new LambdaQueryWrapper<>();

        // 设置日期范围
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        wrapper.between(Appointment::getAppointmentTime, startDateTime, endDateTime);

        // 如果指定了咨询师ID，添加咨询师条件
        if (counselorId != null) {
            wrapper.eq(Appointment::getCounselorId, counselorId);
        }

        // 只查询未删除的记录
        wrapper.eq(Appointment::getDeleted, false);

        // 只查询已确认的预约
        wrapper.eq(Appointment::getStatus, "CONFIRMED");

        // 按预约时间升序排序
        wrapper.orderByAsc(Appointment::getAppointmentTime);

        return list(wrapper);
    }

    @Override
    public List<Appointment> getUpcomingAppointments(LocalDateTime start, LocalDateTime end) {
        return this.lambdaQuery()
            .ge(Appointment::getAppointmentTime, start)
            .le(Appointment::getAppointmentTime, end)
            .eq(Appointment::getStatus, "CONFIRMED")
            .notExists("SELECT 1 FROM chat_session cs WHERE cs.appointment_id = appointment.id")
            .list();
    }

    @Override
    public List<Appointment> getPendingAppointments(Long counselorId) {
        return this.lambdaQuery()
            .eq(Appointment::getCounselorId, counselorId)
            .eq(Appointment::getStatus, "PENDING")
            .eq(Appointment::getDeleted, false)
            .list();
    }

    @Override
    public List<Integer> getWeeklyAppointments() {
        // 获取本周的开始时间（周一）和结束时间（周日）
        LocalDate now = LocalDate.now();
        LocalDate monday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate sunday = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        
        // 查询本周每天的预约数量
        List<Integer> weeklyCount = new ArrayList<>();
        LocalDate current = monday;
        
        while (!current.isAfter(sunday)) {
            LocalDateTime dayStart = current.atStartOfDay();
            LocalDateTime dayEnd = current.plusDays(1).atStartOfDay();
            
            // 统计当天的预约数量
            Long count = baseMapper.selectCount(new LambdaQueryWrapper<Appointment>()
                .between(Appointment::getAppointmentTime, dayStart, dayEnd));
            
            weeklyCount.add(count.intValue());
            current = current.plusDays(1);
        }
        
        return weeklyCount;
    }
    
    @Override
    public List<Map<String, Object>> getConsultationTypeStats() {
        // 定义咨询类型
        Map<String, String> typeMap = new LinkedHashMap<>();
        typeMap.put("ACADEMIC", "学业问题");
        typeMap.put("EMOTIONAL", "情感困扰");
        typeMap.put("PERSONAL", "个人成长");
        typeMap.put("OTHER", "其他");
        
        List<Map<String, Object>> stats = new ArrayList<>();
        
        // 统计每种类型的数量
        for (Map.Entry<String, String> entry : typeMap.entrySet()) {
            Long count = baseMapper.selectCount(new LambdaQueryWrapper<Appointment>()
                .eq(Appointment::getType, entry.getKey())
                .eq(Appointment::getStatus, "CONFIRMED"));
            
            Map<String, Object> typeStats = new HashMap<>();
            typeStats.put("name", entry.getValue());
            typeStats.put("value", count);
            stats.add(typeStats);
        }
        
        return stats;
    }

    @Override
    public Map<String, Object> getAppointmentTrend(Integer days) {
        // 计算日期范围
        LocalDateTime endDate = LocalDateTime.now();
        LocalDateTime startDate = endDate.minusDays(days);
        
        // 查询指定日期范围内的预约
        List<Appointment> appointments = this.lambdaQuery()
            .between(Appointment::getAppointmentTime, startDate, endDate)
            .eq(Appointment::getDeleted, false)
            .list();
        
        // 按日期分组统计
        Map<String, Long> dailyCounts = appointments.stream()
            .collect(Collectors.groupingBy(
                apt -> apt.getAppointmentTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                Collectors.counting()
            ));
        
        // 生成连续的日期列表
        List<String> dateList = new ArrayList<>();
        List<Long> countList = new ArrayList<>();
        
        LocalDate currentDate = startDate.toLocalDate();
        LocalDate endLocalDate = endDate.toLocalDate();
        
        while (!currentDate.isAfter(endLocalDate)) {
            String dateStr = currentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            dateList.add(dateStr);
            countList.add(dailyCounts.getOrDefault(dateStr, 0L));
            currentDate = currentDate.plusDays(1);
        }
        
        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("dates", dateList);
        result.put("counts", countList);
        
        return result;
    }
} 